package main

import "fmt"

// demo10 接口

// 定义接口 约束和 规范 初始化等 全局变量
type Animal interface {
	Eat()
	Run()
}

type Cat struct {
	Name string
	Age  uint
}

type Dog struct {
	Name string
}

func (c Cat) Run() {
	fmt.Println(c.Name + "跑")
}

// 定义结构体中的 函数 需要结构体 Eat
func (c Cat) Eat() {
	fmt.Println(c.Name + "吃")
}

func (d Dog) Run() {
	fmt.Println(d.Name + "跑")
}

func (d Dog) Eat() {
	fmt.Println(d.Name + "吃")
}

// 全局变量
var L Animal

func demo10() {
	fmt.Println("************* 结构体方式 声明方式1 ***********************")
	var a Animal
	c := Cat{
		Name: "猫",
		Age:  18,
	}

	a = c

	fmt.Println(c)

	//  可以用 a声明的结构体变量 调用 获取到 c的变量 也可以用c让它拥有a结构体中的函数
	c.Run()
	a.Eat()

	fmt.Println("************* 结构体方式 声明方式2 ***********************")
	var a1 Animal
	a1 = Cat{
		Name: "狸花猫",
		Age:  22,
	}
	a1.Run()
	a1.Eat()

	fmt.Println("************* 结构体方式 声明方式3 ***********************")
	var a2 Animal = Cat{
		Name: "狸花猫2222",
		Age:  22,
	}
	a2.Run()
	a2.Eat()

	fmt.Println("************* 泛型函数 什么参数都可以接收 ***********************")
	MyFun1("string")
	MyFun1(22222)
	MyFun1(a1)

	fmt.Println("************* 应用场景1 传入不同结构类型 Cat Dog 但是同一个函数都可以满足 通过接口  ***********************")
	c1 := Cat{
		Name: "猫",
		Age:  18,
	}
	MyFun(c1)
	d1 := Dog{
		Name: "狗",
	}
	MyFun(d1)
	fmt.Println("**********  应用场景2 全局变量应用        *************************")

	c33 := Cat{
		Name: "Tom",
		Age:  18,
	}
	MyInit(c33)
	// L全局变量即可拥有函数
	L.Run()
}

// 初始化应用 全局变量
func MyInit(a Animal) {
	L = a
}

// 接口应用函数1 为结构体使执行使其定义好的接口函数规划
// 如果是指定 Cat 那么传入Dog类型就会报错 很明显go应该是没有强制转类型的 需要靠接口做一个通用结构体的封装定义函数
func MyFun(a Animal) {
	a.Run()
	a.Eat()
}

// 泛型函数
func MyFun1(a interface{}) {
	fmt.Println(a)
}
